part of 'store.dart';

void _spawnStoreIsolate(_StoreIsolateConfiguration configuration) async {
  final hiveDirectoryPath = configuration.directoryPath;
  Hive.init(hiveDirectoryPath);

  final receivePort = ReceivePort();
  final receiveStream = receivePort;
  final sendPort = configuration.sendPort;
  sendPort.send(receivePort.sendPort);

  receiveStream.listen((task) async {
    final result = await _handleTask(task);
    sendPort.send(result);

    if (result is _ClosingStoreIsolateTaskResult) {
      receiveStream.close();
    }
  });
}

Future<_StoreIsolateTaskResult> _handleTask(_StoreIsolateTask task) async {
  const boxTitle = 'user_store';

  switch (task) {
    case _MigrationToLastVersionStoreIsolateTask():
      await _handleMigration(
        lastVersion: task.lastVersion,
        directoryPath: task.directoryPath,
      );

      final result = _MigrationToLastVersionStoreIsolateTaskResult(
        taskId: task.id,
      );

      return result;

    case _InitializationStoreIsolateTask():
      await Hive.openLazyBox(
        boxTitle,
        compactionStrategy: (entries, deletedEntries) {
          return deletedEntries >= 50;
        },
      );

      final result = _InitializationStoreIsolateTaskResult(
        taskId: task.id,
      );

      return result;

    case _RecordGettingStoreIsolateTask():
      final value = await Hive.lazyBox(boxTitle).get(task.key);

      final result = _RecordGettingStoreIsolateTaskResult(
        taskId: task.id,
        value: value,
      );

      return result;

    case _RecordSavingStoreIsolateTask():
      try {
        await Hive.lazyBox(boxTitle).put(task.key, task.value);
      } catch (_) {
        // something went wrong
      }

      final result = _RecordSavingStoreIsolateTaskResult(
        taskId: task.id,
      );

      return result;

    case _ClosingStoreIsolateTask():
      await Hive.close();

      final result = _ClosingStoreIsolateTaskResult(
        taskId: task.id,
      );

      return result;

    default:
      throw UnimplementedError();
  }
}

Future<void> _handleMigration({
  required String directoryPath,
  required int lastVersion,
}) async {
  final int? currentVersion;

  final metadataFile = File('$directoryPath/.metadata');
  final metadataFileExists = metadataFile.existsSync();

  if (metadataFileExists) {
    final metadataContent = metadataFile.readAsStringSync();
    final metadataJson = jsonDecode(metadataContent);

    final metadataDto = _StoreContentMetadataDtoFactory().fromJson(metadataJson);

    currentVersion = metadataDto.storeVersion;
  } else if (File('$directoryPath/ru.hive').existsSync()) {
    currentVersion = 1;
  } else {
    currentVersion = null;
  }

  if (currentVersion == lastVersion) {
    return;
  }

  if (currentVersion != null) {
    var migratedVersion = currentVersion;

    if (migratedVersion == 1) {
      await _handleMigrationFromFirstVersionToSecondOne();

      migratedVersion = 2;
    }

    if (migratedVersion < lastVersion) {
      throw UnimplementedError();
    }
  }

  if (!metadataFileExists) {
    metadataFile.createSync(
      recursive: true,
    );
  }

  final metadataDto = _StoreContentMetadataV1Dto(
    storeVersion: lastVersion,
  );

  final metadataJson = metadataDto.toJson();
  final metadataContent = jsonEncode(metadataJson);
  metadataFile.writeAsStringSync(metadataContent);
}
